#pragma once

#include <functional>
#include <cstdint>
#include <sys/epoll.h>
#include <utility>
#include <cassert>
#include <cstring>
#include <unordered_map>

#include "EventLoop.hpp"

#define MAX_EPOLLEVENTS 1024


class EventLoop;
//对外设置监控fd与对应fd的监控事件设置
//事件设置调用后,会传递给epoll等组件处理
class Channel
{
private:
    int _fd;
    EventLoop *_loop;  // Eventloop用于epoll的监控的事件,就绪后的分配
    uint32_t _events;  // 当前需要监控的事件
    uint32_t _revents; // 当前链接触发的事件
    using EventCallback = std::function<void()>;
    EventCallback _read_callback;  // 可读事件被触发的回调函数
    EventCallback _write_callback; // 可写事件被触发的回调函数
    EventCallback _error_callback; // 错误事件被触发的回调函数
    EventCallback _close_callback; // 连接断开事件被触发的回调函数
    EventCallback _event_callback; // 任意事件被触发的回调函数

public:
    Channel(EventLoop *loop,int fd) : _fd(fd), _revents(0), _events(0) ,_loop(loop){}

    int GetFd() { return _fd; }
    int Getevent(){return _events;}   //获取需要监控的事件
    void SetREvents(const uint32_t &event) { _revents = event; }
    void SetReadCallback(const EventCallback &cb) { _read_callback = cb; }
    void SetWriteCallback(const EventCallback &cb) { _write_callback = cb; }
    void SetErrorCallback(const EventCallback &cb) { _error_callback = cb; }
    void SetCloseCallback(const EventCallback &cb) { _close_callback = cb; }
    void SetEventCallback(const EventCallback &cb) { _event_callback = cb; }

  

    // 当前是否监控了可读
    bool ReadAble() { return (_events & EPOLLIN); }
    // 当前是否监控了可写
    bool WriteAble() { return (_events & EPOLLOUT); }
    // 启动读事件监控
    void EnableRead() { _events |= EPOLLIN; Update();}
    // 启动写事件监控
    void EnableWrite() { _events |= EPOLLOUT; Update();}
    // 关闭读事件监控
    void DisableRead() { _events &= ~EPOLLIN; Update();}
    // 关闭写事件监控
    void DisableWrite() { _events &= ~EPOLLOUT; Update();}
    // 关闭所有事件监控
    void DisableAll() { _events = 0; Update();}
  
    //由于此处调用了Epoll内函数，需要在loop类后，channel类外实现
    void Remove();
    void Update();

    // 事件处理，一旦连接触发了事件，就调用这个函数，自己触发了什么事件如何处理自己决定
    void HandleEvent()
    {
        // 读事件就绪（读、关闭、优先数据）
        if ((_revents & EPOLLIN) || (_revents & EPOLLRDHUP) || (_revents & EPOLLPRI))
        {
            if (_read_callback)
                _read_callback();
        }

        /*有可能会释放连接的操作事件，一次只处理一个*/
        
        // 写事件就绪
        if ((_revents & EPOLLOUT))
        {
            if (_write_callback)
                _write_callback();
        }
        // 错误事件就绪
        else if ((_revents & EPOLLERR))
        {
            if(_error_callback)_error_callback();
        }
        //关闭事件就绪
        else if(_revents & EPOLLHUP)
        {
            if(_close_callback) _close_callback();
        }
        //任意事件就绪
        if (_event_callback) _event_callback();
    }
};

//多路转接的基本封装
class Poller
{
private:
    int _epfd;                                    // epoll文件描述符
    struct epoll_event _evs[MAX_EPOLLEVENTS];     // epoll事件数组
    std::unordered_map<int, Channel *> _channels; // 监控fd与对应的channel
private:                                          // 类内方法
    // 对应fd(channel)的事件是否添加事件监控
    bool HasChannel(Channel *channel)
    {
        auto it = _channels.find(channel->GetFd());
        if (it == _channels.end())
            return false;
        return true;
    }

    // 对应fd(channel)监控事件的增删改
    void Update(Channel *channel, int op)
    {
        // int epoll_ctl(int epfd, int op,  int fd,  struct epoll_event *ev);
        int fd = channel->GetFd();
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = channel->Getevent();
        int ret = epoll_ctl(_epfd, op, fd, &ev);
        if (ret < 0)
            ELOG("EPOLLCTL FAILED!");

        return;
    }

public: // 该类外部接口
    Poller()
    {
        _epfd = epoll_create(MAX_EPOLLEVENTS);
        if (_epfd < 0)
        {
            ELOG("EPOLL CREATE FAILED!!");
            abort(); // 退出程序
        }
    }

    // 添加或修改监控事件
    void UpdateEvent(Channel *channel)
    {
        if (!HasChannel(channel))
        {
            // 不存在则添加
            _channels.insert(std::make_pair(channel->GetFd(), channel));
            return Update(channel, EPOLL_CTL_ADD);
        }
        return Update(channel, EPOLL_CTL_MOD);
    }

    // 移除监控
    void RemoveEvent(Channel *channel)
    {
        auto it = _channels.find(channel->GetFd());
        if (it != _channels.end())
        {
            _channels.erase(it);
        }
        return Update(channel, EPOLL_CTL_DEL);
    }

    // 开始监控，传入用于记录就绪的事件的容器（vector）
    void Poll(std::vector<Channel *> *active)
    {
        // int epoll_wait(int epfd, struct epoll_event *evs, int maxevents, int timeout)
        int nfds = epoll_wait(_epfd, _evs, MAX_EPOLLEVENTS, -1);
        if (nfds < 0)
        {
            if (errno == EINTR)return;
           
            ELOG("EPOLL WAIT ERROR:%s\n", strerror(errno));
            abort(); // 退出程序
        }
        for (int i = 0; i < nfds; i++)
        {
            auto it = _channels.find(_evs[i].data.fd);
            assert(it != _channels.end());
            it->second->SetREvents(_evs[i].events); // 设置实际就绪的事件
            active->push_back(it->second);
        }
        return;
    }
};
